#pragma once

template <class T>
struct ScopedTraitDefault {
    static BOOL Destroy(T pObj) {
        delete pObj;
        return TRUE;
    }
};

struct ScopedTraitHandle {
    static BOOL Destroy(HANDLE handle) {
        return ::CloseHandle(handle);
    }
};

struct ScopedTraitModule {
    static BOOL Destroy(HMODULE handle) {
        return ::FreeLibrary(handle);
    }
};

struct ScopedTraitIcon {
    static BOOL Destroy(HICON handle) {
        return ::DestroyIcon(handle);
    }
};

template <class T, class Trait = ScopedTraitDefault<T>>
class ScopedPtr
{
public:
    ScopedPtr()
        : m_pObj(NULL)
    {

    }

    ScopedPtr(T pObj)
        : m_pObj(pObj)
    {

    }

    ~ScopedPtr()
    {
        Set(NULL);
    }

    void Set(T pObj)
    {
        if(NULL != m_pObj) {
            Trait::Destroy(m_pObj);
        }

        m_pObj = pObj;
    }

    T Get()
    {
        return m_pObj;
    }

    operator T()
    {
        return m_pObj;
    }

    T Release()
    {
        T pObj = m_pObj;
        m_pObj = NULL;
        return pObj;
    }

    T * operator &() {
        return &m_pObj;
    }

private:
    T m_pObj;
};

typedef ScopedPtr<HANDLE, ScopedTraitHandle> ScopedHandle;
typedef ScopedPtr<HMODULE, ScopedTraitModule> ScopedModule;
typedef ScopedPtr<HICON, ScopedTraitIcon> ScopedIcon;